package com.topvision.auth.service;

import com.google.common.collect.Maps;
import com.topvision.auth.domain.SysUser;
import com.topvision.auth.domain.SysUserAccount;
import com.topvision.common.exception.BusinessException;
import com.topvision.common.security.SecurityErrorPrompt;
import com.topvision.common.security.UserInfo;
import com.topvision.common.token.JWTFilter;
import com.topvision.common.token.RawAccessToken;
import com.topvision.common.token.RefreshToken;
import com.topvision.common.token.TokenProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author shengwm
 * @version V0.0.1
 * @Title: LoginService
 * @Package com.seed.security.service
 * @Description: TODO
 * @date 2017/6/16
 */
@Service
@Slf4j
public class LoginService {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private TokenProvider tokenProvider;
    //@Autowired
    private JWTFilter jwtFilter;

    @Autowired
    private  SysUserService sysUserService;

    @Autowired
    private SysUserAccountService sysUserAccountService;
    @Autowired
    private BCryptPasswordEncoder encoder;

    /**
     * 授权登录
     *
     * @param username
     * @param password
     * @param isRememberMe
     * @return
     */
    public Map<String, Object> authorize(String username, String password, Boolean isRememberMe) {
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username, password);
        try {
            Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            boolean rememberMe = (isRememberMe == null) ? false : isRememberMe;
            // 生成token
            Map<String, Object> map = tokenProvider.createAccessToken(authentication, rememberMe);

            // 附加信息
            UserInfo userInfo = (UserInfo) authentication.getPrincipal();
           /* User user =(User)authentication.getPrincipal();
            UserInfo userInfo = new UserInfo();
            userInfo.setUsername(user.getUsername());
            userInfo.setAuthorities(user.getAuthorities());
            userInfo.setPassword(user.getPassword());
            userInfo.setEnabled(true);*/


            Map<String, Object> info = Maps.newHashMap();
            info.put("userNo", userInfo.getUsername());
            info.put("name", userInfo.getName());
            info.put("mobile", userInfo.getMobile());
           // info.put("defaultPassword",userInfo.getDefaultPassword());

            map.put("info", info);
            return map;
        } catch (AuthenticationException e) {
            // 授权异常
            log.trace("Authentication exception trace: {}", e);
            throw new BusinessException("authen_error", e.getLocalizedMessage());
        }
    }

    /**
     * 刷新token
     *
     * @param bearerToken
     * @return
     */
    public Map<String, Object> refreshToken(String bearerToken) {
        String tokenPayload = jwtFilter.extract(bearerToken);

        RawAccessToken rawToken = new RawAccessToken(tokenPayload);
        RefreshToken refreshToken = RefreshToken.createRefreshToken(rawToken).orElseThrow(() -> new BusinessException());

        String subject = refreshToken.getSubject();

        try {
            // 获取用户账号
            SysUserAccount userAccount = sysUserAccountService.findUserAccount(subject);

            // 获取用户信息
            SysUser user = sysUserService.findById(userAccount.getUserId());


            // 获取用户授权信息
            List<GrantedAuthority> authorities = user.getAuthorities().stream().collect(Collectors.toList());

            // 没有权限则登录失败
            if (authorities.isEmpty()) {
                throw new BusinessException(SecurityErrorPrompt.SEED_MICRO_SECURITY_STATUS_10005.getValue(), SecurityErrorPrompt.SEED_MICRO_SECURITY_STATUS_10005.getLabel());
            }

            UserInfo userContext = UserInfo.create(subject, authorities);
            return tokenProvider.createAccessToken(userContext, false);
        } catch (AuthenticationException e) {
            log.trace("refresh token error: {}", e.getMessage());
            throw new BusinessException("refresh_token_error", e.getLocalizedMessage());
        }
    }

    /**
     * 第三方认证登录
     *
     * @param username
     * @param password
     * @param isRememberMe
     * @return
     */
    public Map<String, Object> login(String username, String password, Boolean isRememberMe) {
        try {
            // 获取用户账号
            SysUserAccount userAccount = sysUserAccountService.findUserAccount(username);

            //  验证用户密码
            if (!encoder.matches(password, userAccount.getPassword())) {
                throw new BusinessException(SecurityErrorPrompt.SEED_MICRO_SECURITY_STATUS_10003.getValue(), SecurityErrorPrompt.SEED_MICRO_SECURITY_STATUS_10003.getLabel());
            }

            // 获取用户信息
            SysUser user = sysUserService.findById(userAccount.getUserId());


            Map<String, Object> map = Maps.newHashMap();
            map.put("userNo", user.getId());
            map.put("name", user.getUsername());
            return map;
        } catch (AuthenticationException e) {
            // 授权异常
            log.trace("Authentication exception trace: {}", e);
            throw new BusinessException("authen_error", e.getLocalizedMessage());
        }
    }
}
